#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <pthread.h>
#include "include/my_global.h"
#include "include/my_sys.h"
#include "server_global.h"
#include "include/mysql.h"

pthread_mutex_t gtrid_mutex_lock;

extern int gtrid;
/* Open group/XA unique global transaction flag */
int dp_get_gtrid(void)
{
    return ++gtrid;
}


int xa_start(MYSQL *mysql, char *gtrid)
{
  char start[0xff];
  sprintf(start, "%s '%s'", "xa start", gtrid);
  if (mysql_real_query(mysql, start, (unsigned int) strlen(start)))
  {
    dp_log_error("Xa start failed: host:%s, gtrid:%s, %s, %d\n",
           mysql->host, start, mysql_error(mysql), mysql_errno(mysql));
    return 1;
  }
  return 0;
}

int xa_end(MYSQL *mysql, char *gtrid)
{
  char end[0xff];
  sprintf(end, "%s '%s'", "xa end", gtrid);
  if (mysql_real_query(mysql, end, strlen(end)))
  {
    dp_log_error("Xa end failed: host:%s, gtrid:%s, %s, %d\n",
           mysql->host, end, mysql_error(mysql), mysql_errno(mysql));
    return mysql_errno(mysql);
  }
  return 0;
}

int xa_prepare(MYSQL *mysql, char *gtrid)
{
  char prepare[0xff];
  sprintf(prepare, "%s '%s'", "xa prepare", gtrid);
  if (mysql_real_query(mysql, prepare, strlen(prepare)))
  {
    dp_log_error("Prepare failed: host:%s, gtrid:%s, %s, %d\n",
           mysql->host, prepare, mysql_error(mysql), mysql_errno(mysql));
    return 1;
  }
  return 0;
}

int xa_rollback(MYSQL *mysql, char *gtrid)
{
  char rollback[0xff];
  sprintf(rollback, "%s '%s'", "xa rollback", gtrid);
  if (mysql_real_query(mysql, rollback, strlen(rollback)))
  {
    dp_log_error("Rollback failed: host:%s, gtrid:%s, %s, %d\n",
           mysql->host, rollback, mysql_error(mysql), mysql_errno(mysql));
    return 1;
  }
  return 0;
}

int xa_commit(MYSQL *mysql, char *gtrid)
{
  char commit[0xff];
  sprintf(commit, "%s '%s'", "xa commit", gtrid);
  if (mysql_real_query(mysql, commit, strlen(commit)))
  {
    dp_log_error("Commit failed: host:%s, gtrid:%s, %s, %d\n",
           mysql->host, commit, mysql_error(mysql), mysql_errno(mysql));
    return 1;
  }
  return 0;
}

/*
 * 
 */
int trx_proc(int pos, int range)
{
  MYSQL master, andy;
  char gtrid[0xf];
  char query[] = "insert into xa_test values()";

  int begin = pos;
  int end = begin + range;

  if (NULL == mysql_init(&master)
      || NULL == mysql_init(&andy))
  {
    return 1;
  }
  master.reconnect= andy.reconnect= 1;

  if (!mysql_real_connect(&master, "172.17.4.48", "dba", "yvhkfhvk", "shell", 3333, NULL, 0)
      || !mysql_real_connect(&andy, "172.17.4.50", "dba", "yvhkfhvk", "shell", 3333, NULL, 0))
  {
    dp_log_error("Connect failed.\n");
    dp_log_error("Rollback failed: gtrid:%s, %s, %d\n",
           gtrid, mysql_error(&master), mysql_errno(&master));

    return 1;
  }

  for ( ; begin < end; begin++)
  {
    sprintf(gtrid, "xa%d", begin);

    if (xa_start(&master, gtrid) || xa_start(&andy, gtrid))
    {
      dp_log_error("XA start failed.\n");
      return 1;
    }

    if (mysql_real_query(&master, query, strlen(query)))
    {
      dp_log_error("%s, %s, %d\n", query, mysql_error(&master), mysql_errno(&master));
      return 1;
    }

    if (mysql_real_query(&andy, query, strlen(query)))
    {
      dp_log_error("%s, %s, %d\n", query, mysql_error(&andy), mysql_errno(&andy));
      return 1;
    }

    if ( xa_end(&master, gtrid) ||  xa_end(&andy, gtrid))
    {
      dp_log_error("xa end failed.\n");
      return 1;
    }

    if ( xa_prepare(&master, gtrid))
    {
      dp_log_error("Prepare master failed. Xa the end.\n");
      return 1;
    }

    if ( xa_prepare(&andy, gtrid))
    {
      dp_log_error("Prepare andy failed. Rollback master.\n");
      return xa_rollback(&master, gtrid);
    }

    if ( xa_commit(&master, gtrid))
    {
      dp_log_error("xa commit failed.\n");
      return xa_rollback(&andy, gtrid);
    }

    if ( xa_commit(&andy, gtrid))
    {
      dp_log_error("Xa laste commit failed.\n");
      goto err;
    }

  }
  dp_log_error("XA STRANSACTION EXEC SUCCESS.\n");
err:
  mysql_close(&master);
  mysql_close(&andy);
  return (EXIT_SUCCESS);
}

void *xxoo(void *agc)
{
  int tid = *(int *) agc;
  trx_proc(tid * 10000, 9999);
  pthread_exit(NULL);
}

int main(int argc, char **argv)
{
  int i = 0;
  int tt[0xfff];
  pthread_t thd[0xfff];
  int res, max_thread=20;

  if (par)
  {
    int procs = atoi(argv[1]);
    max_thread=procs;
  }
  dp_log_error("create thread start.\n");
  for (i = 0; i < max_thread; i++)
  {
    tt[i] = i + 1;
    res = pthread_create(&thd[i], NULL, xxoo, &tt[i]);
    if (res)
    {
      dp_log_error("thread create failed\n");
    }
  }

  dp_log_error("thread num = %d\n", i);
  for ( i-- ; i > 0; i--)
  {
    pthread_join(thd[i], NULL);
  }
  dp_log_error("TEST END\n");
  return 0;
}
